// WhiteboardPanel.java

/*
**  Licensed Materials - Property of IBM
**
**  (C) COPYRIGHT IBM Corp. 1996, 1997  All rights reserved
**
**  US Government Users Restricted Rights - Use, duplication or
**  disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
**
**/

package	com.ibm.tspaces.examples.whiteboard;

import java.awt.event.*;
import java.awt.*;
import java.applet.*;
import java.util.*;
import com.ibm.tspaces.*;

/**
** The panel of the whiteboard.
** 
** This handles the panel where the lines and points are 
** drawn. 
**
** All of the TSpaces handling is done inside this object.
** 
** It implements the Tuplespace Callback interface which gets 
** control everytime a matching request is issued to TupleSpace.
**
** 
**  
** @version $Revision: 2.1.2.1 $ $Date: 2000/02/05 14:52:31 $
** @author <a href="mailto:eichstam@almaden.ibm.com">Matthias Eichstaedt</a>
** @author <a href="mailto:jthomas@cruzio.com">John Thomas</a>
*/
public class WhiteboardPanel extends Panel 
		implements MouseListener, MouseMotionListener, Callback {

    public static final int LINES = 0;
    public static final int POINTS = 1;
    int	   mode = LINES;
    Vector linesOld = new Vector();
    Vector colorsOld = new Vector();
    
    Vector linesNew = new Vector();
    Vector colorsNew = new Vector();
    
    protected static Color BACKGROUND_COLOR = Color.white;
    int x1, y1;
    int x2, y2;
    int xl, yl;
    private Whiteboard whiteboard = null;
	private WhiteboardControls Controls = null;
	/**
	** This holds a reference to the current TupleSpace.
	*/
	protected TupleSpace TSServer = null;
	
	/** 
	** This is the Host where the TupleSpace Server is running
	*/
	protected String Host = TupleSpace.DEFAULTHOST;
	/**
	** This is the port number for the TupleSpace server.
	** The TupleSpace HTTP Server is at this port +1
	*/ 
	protected int Port = TupleSpace.DEFAULTPORT;
	
	protected boolean EraseFlag = false;   // set true when erase command received
    protected boolean NotActive = false;   // set true if server is not active
    protected boolean Failed = false;      // set true if something fails/exception
    /*
    ***************************************************************************
    ** ** WhiteboardPanel **
    ** *********************
    */
    /**
    ** The constructor 
    **
    *************************************************************************** 
    */
    public WhiteboardPanel() {
      
        
    } // WhiteboardPanel
    
/**
** TupleSpace Initiallization routine.
**
** This will setup to access TupleSpace and register to 
** be informed when anyone writes a "Whiteboard" tuple to 
** the "Whiteboard" tuplespace.
** 
** It will then get all the current Tuples and paint them.
**
** TupleSpace contains the all of the whiteboard tuples that 
** have been written up to this time.  We want to read in and 
** process all of them.  We use the scan method for this and 
** get back a tuple that is a list of the tuples.
**
** @see TupleSpace
** @see Tuple
** @see Field
*/
public void 
init(Whiteboard caller) {
	// Place the controls at the top of the parent window
	//System.out.println("init entered");
	Controls = new WhiteboardControls(this);
	caller.add("North",Controls);

	setBackground(BACKGROUND_COLOR);
    addMouseMotionListener(this);
    addMouseListener(this);
    
    // Handle the user exiting/killing the application
    if ( caller.appFrame != null ) 
	    caller.appFrame.addWindowListener( new WindowAdapter()  {
	    	public void 
	    	windowClosing (WindowEvent e) {
          System.out.println("Window Close event");
	    		WhiteboardPanel.this.term();    // give it a chance to cleanup
	    		//System.exit(0);
	    	}
	    } );
   

    this.whiteboard = caller;
    // The host and port may have already been set in whiteboard.java
    if (Whiteboard.host != null)
       	Host = Whiteboard.host; 
    if (Whiteboard.port > 0)	
       	Port = Whiteboard.port;
    Vector lines = new Vector(0);
    Vector colors = new Vector(0);            
    int n=0;
    String Msg = null;
 	  try {
	
      //--------------------------------------------------
      // Setup to access TupleSpace
      // We access the "Whiteboard" tuplespace on the indicatd host.
      //
      // We then just register for the write event 
      //   Whiteboard.wp must implement Callback which will then
      //   be called anytime anyone writes a matching tuple to the tuplespace 
      //------------------------------------------------------------
      System.out.println("Access Whiteboard tuplespace at " + Host+":"+Port);
      String user = TupleSpace._DEFAULT_USER;
      String pass = TupleSpace._DEFAULT_PASSWORD;
      //  Tell the TupleSpace code that we are going to be running 
       //  in an applet sandbox and to avoid any otion that is 
       //  invalid.
      TupleSpace.appletEnvironment(true);
      String version = TupleSpace.getVersion();
      System.out.println(version);
      
    
      TupleSpace.setConnectionTries(1);
 	/******  
      // Verify that the Server is active
    Tuple active = TupleSpace.status(Host,Port);
    System.out.println("Status="+active);
      // status() returns a simple Tuple that contains "Running" or "NotRunning"
    if ( active == null || active.getField(0).getValue().equals("NotRunning")) { 
      System.out.println("TSpaces server not running on " + 
            Host+":"+Port );
        NotActive = true;
    }
  *******/ 
      //TSServer = new TupleSpace("Whiteboard", Host,Port,null,null,user,pass);
       TSServer = new TupleSpace("Whiteboard", Host,Port);
  
	    // create dummy template and do a test read to see if it fails
      try {
        Tuple match = new Tuple("Whiteboard"); 
                
        Tuple result = TSServer.read(match);
      } catch (TupleSpaceException tse) {
        System.out.println("TSpaces server not running on " + 
              Host+":"+Port );
          NotActive = true;
          
      }
      if ( ! NotActive)  {    
    
        // create a template to indicate what we are interested in
        Tuple match = new Tuple("Whiteboard", 
                  new Field(Vector.class),
                  new Field(Vector.class)  );
            // place ourselves on the list to notified when anyone anywhere
            // writes a matching Tuple to this TupleSpace.            
        int seqNum = TSServer.eventRegister(TupleSpace.WRITE,match, this);
      }
    } catch(TupleSpaceException tse) {
        System.out.println("TupleSpaceException " + tse);    	
        tse.printStackTrace();
        Msg = tse.getMessage();
        Failed = true;
    } catch (Exception e)  { 
     	System.out.println("Exception " + e);
     	e.printStackTrace();
     	Msg = e.getMessage();
     	Failed = true;
	} catch (Error err)  { 
     	System.out.println("Error " + err);
     	err.printStackTrace();
     	Msg = err.getMessage();
     	Failed = true;
	}
    
  if (NotActive) {
    Label errmsg = new Label("TSpaces server is not available for communication");
    caller.add("South",errmsg);
    Controls.setPublish(false);
    Controls.setErase(false);  
    caller.setVisible(true);
    
    return;
  }
  if (Failed) {
    Label errmsg = new Label("TSpaces connection failure: "+ Msg);
    caller.add("South",errmsg);
    Controls.setPublish(false);
    Controls.setErase(false);  
    caller.setVisible(true);      
    return;
  }

    
    //System.out.println("Scan for current status");
    //
    // During initialization, we need to read all the current line and color
	// Vectors stored at the TSpaces server. So we issue the 
	// scan() request to the tupleSpace using a template. This returns
	// a tuple whose fields are each tuples, one for each tuple that matched the
	// template. The tuple.fields() method returns an enumeration that can be
	// followed to access each individual Tuple. Once the individual Tuple is
	// accessed, the getFields(int) method is used to access the line and color
	// Vectors from the 2nd and 3rd field. 

	try {
		// create a template to indicate what we are interested in
    	Tuple match = new Tuple("Whiteboard", 
    						new Field(Vector.class),
    						new Field(Vector.class) );
        // Issue the TupleSpace.scan() command.
		Tuple tupleSet = TSServer.scan(match);
		if ( tupleSet != null) {
			// Each Field of tupleSet is one of the Whiteboard tuples
			Enumeration e = tupleSet.fields();    
			while (	e.hasMoreElements() ) { 
				// enumerate over the set of tuples
				Field f = (Field)e.nextElement();
				//System.out.println("Tuple " + f);
				// So now we get have one of the Whitespace tuples which 
				// contains 2 vectors.  One for lines, one for colors
				Tuple tuple = (Tuple)f.getValue();				
				lines = (Vector)tuple.getField(1).getValue();
        		colors = (Vector)tuple.getField(2).getValue();
        		n = lines.size();
        		// copy the lines and colors to the Vectors that we maintain.
    			for (int i=0;i<n;i++) {
    				linesOld.addElement(lines.elementAt(i));
    				colorsOld.addElement(colors.elementAt(i));
    			}
	
			}
		}
        
    } // try
    catch(TupleSpaceException tse) {
        System.out.println("com.ibm.tspaces.examples.whiteboard.WhiteboardPanel::call TupleSpaceException " + tse.getMessage());
    	Failed = true;
    } // catch
    if (Failed) {
    	Label errmsg = new Label("TSpaces interface failure");
    	caller.add("South",errmsg);
    	Controls.setPublish(false);
    	Controls.setErase(false);	
    	caller.setVisible(true);    	
    	return;
    }

    //System.out.println("Now paint initial screen");
    mode = -1;
    Graphics g = this.getGraphics();
    if ( g == null)  {
    	System.out.println("No graphic context");
    	setDrawMode(LINES);
    	return;
    }	
    this.paint(g);
    setDrawMode(LINES);
    

} // init
  

    /*
    ***************************************************************************
    ** ** term **
    ** *****************
    */
    /**
    ** This is called when the windowClosing event 
    ** arrives.  We will tell the server that we are going away by 
    ** issuing the cleanup() command.
    ** 
    ** @see TupleSpace#cleanup
    ** 
    *************************************************************************** 
    */
public void
term() {
	//System.out.println("term()");
	try {
		
		TSServer.cleanup();
    Thread.sleep(1000);
    if (Whiteboard.application) 
      System.exit(1);
	} catch (Exception tse) {
		System.out.println("term(): " + tse.getMessage());
		tse.printStackTrace();
	}
}  

	/*
    ***************************************************************************
    ** ** removeAll **
    ** *****************
    */
    /**
    ** This is called our parent (Whiteboard) gets a applet destroy()
    ** event.  We will tell the server that we are going away by 
    ** issuing the term() command.
    **     
    *************************************************************************** 
    */
public void
removeAll() {
	super.removeAll();
	term();
	
}  
 
    /*
    ***************************************************************************
    ** ** publish **
    ** *************
    */
    /**
    ** Publish the current content to tuplespace.
    **    
    ** This will write the vector of lines and colors that the user
    ** has created since the last publish.   It will then start a new 
    ** set of lines and colors.  
    **  
    ** Since we will be informed of our own write in the callback,
    ** we will let the callback update the set of all lines. 
    *************************************************************************** 
    */
    public void publish() {
    	//System.out.println("Publish: lines="+linesNew.size());
    	if (linesNew.size() == 0) 
    		return;
        try {
        	Tuple publish = new Tuple("Whiteboard", linesNew, colorsNew);
        	//System.out.println("publish="+publish);
            TSServer.write(publish);
        } // try
        catch(TupleSpaceException tse) {
            System.out.println("TupleSpaceException: " + tse.getMessage());
            Failed = true;
        } // catch
        
        linesNew = new Vector(20);
        colorsNew = new Vector(20);
    } // publish



	/*
    ***************************************************************************
    ** ** erase **
    ** *************
    */
    /**
    ** Erase the lines that the User has drawn since last Publish.
    **    
    ** 
    *************************************************************************** 
    */
    public void erase() {
    	
    	linesNew = new Vector(20);
    	colorsNew = new Vector(20);
     
        EraseFlag = true;
        
		// Now go repaint the screen.
        Graphics g = this.getGraphics();
        int savemode = mode;
        mode = -1;
        this.paint(g);
        setDrawMode(savemode);

        
    } // erase
	/*
    ***************************************************************************
    ** ** eraseAll **
    ** *************
    */
    /**
    ** Global Erase of the whiteboard.
    **    
    ** This will write a empty vector of lines and colors 
    ** to tuplespace.  This will be treated as an erase command
    ** by other clients that receive the request.  
    ** We will also delete all of the old lines and points that have
    ** been accumulating in the TupleSpace.
    **  
    ** Since we will be informed of this in the callback,
    ** we will let the callback update the set of all lines.
    **
    ** We won't worry about problems caused by requests arriving at the 
    ** the server and clients in different orders.   
    *************************************************************************** 
    */
    public void eraseAll() {
    
    	linesNew = new Vector(20);
    	colorsNew = new Vector(20);
    	
        try {
        	// Tell all clients that we did an erase.
            TSServer.write("Whiteboard", linesNew, colorsNew);
        	// Delete all the whiteboard tuples
        	TSServer.deleteAll();
        
        } // try
        catch(TupleSpaceException tse) {
            System.out.println("TupleSpaceException");
            System.out.println(tse.getMessage());
            Failed = true;
        } // catch
       
        

    } // eraseAll
    /*
    ***************************************************************************
    ** ** exitCmd **
    ** *************
    */
    public void exitcmd() {
      
      System.out.println("Exiting");
      term();
      //System.exit(1);
    }
    /**


    /*
    ***************************************************************************
    ** ** call **
    ** **********
    */
    /**
    ** Process the callback from the server that notifies us when anyone 
    ** (including ourselfes) writes to the Whiteboard TupleSpace.
    ** If we get back 2 empty vectors, then this was an erase request
    ** from one of our users.  Otherwise, the 2 vectors are the
    ** lines/points and colors that one of our users is publishing
    ** 
    ** @param eventName_ the name of the event command that caused this call, that is the
    ** name of the client side command of the thread that registered this call, e.g., in the
    ** case of a read, this would be TupleSpace.READ, **not** TupleSpace.WRITE which is the
    ** corresponding command that caused the actaul event.
    ** @param tsName_ the name of the tuple space this command was executed on.
    ** @param sequenceNumber_ the sequenceNumber for this event/command
    ** @param tuple_ the returned tuple or a Tuple with an exception inside
    ** @param isException_ was the command processed normaly or was there an exception
    **
    ** @return true if this is the last call this sequence # should be getting otherwise false
    *************************************************************************** 
    */
    public synchronized boolean 
    call(String eventName_, String tsName_, int sequenceNumber_, SuperTuple tuple_, 
										boolean isException_) {
		Vector lines = null;
		Vector colors = null;						
		// Normally we should wake up some other
		// thread and queue up the info for it.
		// Remember, this code is being run in the thread
		// that handles callbacks from the server so make it quick here please.
	/****	
		System.err.println("callback for " + eventName_ 
			 + ", TupleSpace = " + tsName_  
			 + ",Seq #=" + sequenceNumber_  
			 + ",Tuple="  +	 tuple_ 
			 + ", isException=" + isException_);
	****/

	    // Get the 2 vectors from the Tuple that we recieved.
		try {
      if ( isException_ ) {  // report of an exception 
        Throwable e = (Throwable)(tuple_.getField(0).getValue());
        System.out.println("Callback received Exception: "+ e);
        term();
        return true;
      }
      lines = (Vector)(tuple_.getField(1).getValue());
      colors = (Vector)(tuple_.getField(2).getValue());
    
      int np = lines.size();
      //System.out.println("Call: lines="+np);
      
      if ( np == 0) {  
          // Process an erase request
        System.out.println("Erase Request recieved from server");
        linesOld = new Vector(100);
        colorsOld = new Vector(100);
        EraseFlag = true;
      } else {
        System.out.println("Publish Request recieved from server");
          for (int i=0;i<np;i++) {
            linesOld.addElement(lines.elementAt(i));
            colorsOld.addElement(colors.elementAt(i));
          }
      }
      // Now go repaint the screen.
      Graphics g = this.getGraphics();
      int savemode = mode;
      mode = -1;
      this.paint(g);
      setDrawMode(savemode);
      // If this is a regular callback, NOT an event callback then return
      // true. Regular callbacks are for blocking reads and takes which are
      // one time only callbacks and thus the true tells the TupleSpace to
      // remove this Callback object from its hashtable.  But we want to 
      // continue recieving requests so we will return false.
      return false;
    } catch(TupleSpaceException tse) {
      System.out.println("com.ibm.tspaces.examples.whiteboard.WhiteboardPanel::call TupleSpaceException " + tse.getMessage());
      Failed = true;
      return false;
    } // catch    
  } // call
    
        /*
    ***************************************************************************
    ** ** paint **
    ** ***********
    */
    /**
    ** Paints the panel.  
    ** The real paint method is called first for the objects that
    ** this user has generated, and then for a vector of objects
    ** that have been recieved form TupleSpace.
    **
    ** If an Erase request was received from TupleSpace then the 
    ** EraseFlag was set and we will erase the window before 
    ** proceeding.  
    **
    ** @param g - the graphics context
    *************************************************************************** 
    */
    public void paint(Graphics g) {
    	//System.out.println("paint() ");
    	if ( ! Whiteboard.PaintOK )   // If iconified
    		return;
    	if (EraseFlag) {
    		g.setColor(BACKGROUND_COLOR);
			g.fillRect(0,0,getSize().width,getSize().height);
			EraseFlag = false;
		}
	
    	paint(g,linesNew,colorsNew);
    	paint(g,linesOld,colorsOld);
    	if (Failed) {
    		//System.out.println("TSpaces interface failure");
    		Label errmsg = new Label("TSpaces interface failure");
	    	this.whiteboard.add("South",errmsg);
	    	Controls.setPublish(false);
	    	Controls.setErase(false);
	    	this.whiteboard.invalidate();
	    	this.whiteboard.doLayout();	
	    	this.whiteboard.setVisible(true);	    	
	    	return;
	    }
	
    }
    
     /*
    ***************************************************************************
    ** ** paint **
    ** ***********
    */
    /**
    ** Paints the panel based on the vectos of lines and colors.
    **
    ** @param g - the graphics context
    ** @param lines - A vector of Rectangle objects
    ** @param colors - A vector of color objects.
    *************************************************************************** 
    */

    public void paint(Graphics g,Vector lines, Vector colors) {
        int np = lines.size();
	
        /* draw the current lines */
        
        g.setColor(getForeground());
        
        g.setPaintMode();
        for (int i=0; i < np; i++) {
            Rectangle p = (Rectangle)lines.elementAt(i);
            g.setColor((Color)colors.elementAt(i));
            if (p.width != -1) {
                g.drawLine(p.x, p.y, p.width, p.height);
            } else {
                g.drawLine(p.x, p.y, p.x, p.y);
            } // if
        } // for
        if (mode == LINES) {
            g.setXORMode(getBackground());
            if (xl != -1) {
                /* erase the last line. */
                g.drawLine(x1, y1, xl, yl);
            } // if
            g.setColor(getForeground());
            g.setPaintMode();
            if (x2 != -1) {
                g.drawLine(x1, y1, x2, y2);
            } // if
        } // if
    } // paint


    
    /*
    ***************************************************************************
    ** ** setDrawMode **
    ** *****************
    */
    /**
    ** Set the draw mode.
    **
    ** @param mode - the draw mode
    *************************************************************************** 
    */
    public void setDrawMode(int mode) {
        switch (mode) {
        case LINES:
        case POINTS:
            this.mode = mode;
            break;
        default:
            throw new IllegalArgumentException();
        } // switch
    } // setDrawMode

    /*
    ***************************************************************************
    ** ** mouseDragged **
    ** ******************
    */
    /**
    ** The mouse was dragged.
    **
    ** @param e - the mouse event
    *************************************************************************** 
    */
    public void mouseDragged(MouseEvent e) {
        e.consume();
        switch (mode) {
        case LINES:
            xl = x2;
            yl = y2;
            x2 = e.getX();
            y2 = e.getY();
        break;
        case POINTS:
        default:
            colorsNew.addElement(getForeground());
            linesNew.addElement(new Rectangle(x1, y1, e.getX(), e.getY()));
            x1 = e.getX();
            y1 = e.getY();
            break;
        } // switch
        repaint();
    } // mouseDragged

    /*
    ***************************************************************************
    ** ** mouseMoved **
    ** ****************
    */
    /**
    ** The mouse was moved.
    **
    ** @param e - the mouse event
    *************************************************************************** 
    */
    public void mouseMoved(MouseEvent e) {
        // not much to do here
    } // mouseMoved

    /*
    ***************************************************************************
    ** ** mousePressed **
    ** ******************
    */
    /**
    ** The mouse button was pressed.
    **
    ** @param e - the mouse event
    *************************************************************************** 
    */
    public void mousePressed(MouseEvent e) {
        e.consume();
        switch (mode) {
        case LINES:
            x1 = e.getX();
            y1 = e.getY();
            x2 = -1;
            break;
        case POINTS:
        default:
            colorsNew.addElement(getForeground());
            linesNew.addElement(new Rectangle(e.getX(), e.getY(), -1, -1));
            x1 = e.getX();
            y1 = e.getY();
            repaint();
            break;
        } // break
    } // mousePressed

    /*
    ***************************************************************************
    ** ** mouseReleased **
    ** *******************
    */
    /**
    ** The mouse button was released.
    **
    ** @param e - the mouse event
    *************************************************************************** 
    */
    public void mouseReleased(MouseEvent e) {
        e.consume();
        switch (mode) {
        case LINES:
            colorsNew.addElement(getForeground());
            linesNew.addElement(new Rectangle(x1, y1, e.getX(), e.getY()));
            x2 = xl = -1;
        break;
        case POINTS:
        default:
            break;
        } // switch
        repaint();  
    } // mouseReleased

    /*
    ***************************************************************************
    ** ** mouseEntered **
    ** ******************
    */
    /**
    ** The mouse entered this panel.
    **
    ** @param e - the mouse event
    *************************************************************************** 
    */
    public void mouseEntered(MouseEvent e) {
    } // mouseEntered

    /*
    ***************************************************************************
    ** ** mouseExited **
    ** *****************
    */
    /**
    ** The mouse left this panel.
    **
    ** @param e - the mouse event
    *************************************************************************** 
    */
    public void mouseExited(MouseEvent e) {
    } // mouseExited

    /*
    ***************************************************************************
    ** ** mouseClicked **
    ** ******************
    */
    /**
    ** The mouse button was clicked.
    **
    ** @param e - the mouse event
    *************************************************************************** 
    */
    public void mouseClicked(MouseEvent e) {
    } // mouseClicked


} // WhiteboardPanel

/*
$History: WhiteboardPanel.java $
 * 
 * *****************  Version 7  *****************
 * User: Jthomas      Date: 2/03/99    Time: 11:06a
 * Updated in $/GCS/Development/TSpaces/Java/com/ibm/tspaces/examples/whiteboard
 * call appletEnvironment(true)
 * 
 * *****************  Version 6  *****************
 * User: Jthomas      Date: 1/29/99    Time: 9:45a
 * Updated in $/GCS/Development/TSpaces/Java/com/ibm/tspaces/examples/whiteboard
 * - chances for new Field  method names
 * - Use of new  if Debug.ON 
 * 
 * *****************  Version 5  *****************
 * User: Jthomas      Date: 10/14/98   Time: 9:48a
 * Updated in $/GCS/Development/TSpaces/Java/com/ibm/tspaces/examples/whiteboard
 * Use static methods
 * 
 * *****************  Version 4  *****************
 * User: Jthomas      Date: 4/24/98    Time: 10:20a
 * Updated in $/GCS/Development/TSpaces/Java/com/ibm/tspaces/examples/whiteboard
 * changes for 1.1, cleanup, debug info
 * 
 * *****************  Version 3  *****************
 * User: Jthomas      Date: 3/11/98    Time: 5:41p
 * Updated in $/GCS/Development/TSpaces/Java/com/ibm/tspaces/examples/whiteboard
 * remove status check because it takes admin authority
 * 
 * *****************  Version 2  *****************
 * User: Jthomas      Date: 3/09/98    Time: 1:57p
 * Updated in $/GCS/Development/TSpaces/Java/com/ibm/tspaces/examples/whiteboard
 * makeField to obj.class
 * 
 * *****************  Version 1  *****************
 * User: Toby         Date: 1/23/98    Time: 9:56a
 * Created in $/GCS/Development/TSpaces/Java/com/ibm/tspaces/examples/whiteboard
 * 
 * *****************  Version 12  *****************
 * User: Jthomas      Date: 1/05/98    Time: 2:23p
 * Updated in $/GCS/Development/bluespaces/Java/com/ibm/bluespaces/examples/whiteboard
 * Replace Erase button with Erase/EraseAll 
 * Bypass the Vector Serialization bug
 * 
 * *****************  Version 11  *****************
 * User: Jthomas      Date: 12/10/97   Time: 8:24a
 * Updated in $/GCS/Development/bluespaces/Java/com/ibm/bluespaces/examples/whiteboard
 * Handle start/stop/destroy methods
 * Display msg to user on any exception 
 * 
 * *****************  Version 10  *****************
 * User: Jthomas      Date: 12/03/97   Time: 11:46p
 * Updated in $/GCS/Development/bluespaces/Java/com/ibm/bluespaces/examples/whiteboard
 * remove import statement for ts server 
 * 
 * *****************  Version 8  *****************
 * User: Jthomas      Date: 11/26/97   Time: 4:41p
 * Updated in $/GCS/Development/bluespaces/Java/com/ibm/bluespaces/examples/whiteboard
 * Whiteboard - fix for browsers that don't support JDK 1.1
 * 
 * *****************  Version 7  *****************
 * User: Jthomas      Date: 11/24/97   Time: 10:48a
 * Updated in $/GCS/Development/bluespaces/Java/com/ibm/bluespaces/examples/whiteboard
 * Lots of changes:
 *    Moved all TupleSpace code to WhiteboardPanel
 *    Added Erase feature
 *    Only write new Lines and points to TS
 *    Handle host/port
 *    misc
 * 
 * *****************  Version 6  *****************
 * User: Jthomas      Date: 11/18/97   Time: 5:02p
 * Updated in $/GCS/Development/bluespaces/Java/com/ibm/bluespaces/examples/whiteboard
 * comment out large print statemnent
 * 
 * *****************  Version 5  *****************
 * User: Jthomas      Date: 11/18/97   Time: 10:25a
 * Updated in $/GCS/Development/bluespaces/Java/com/ibm/bluespaces/examples/whiteboard
 * Changes so that it works as an applet and an application
 * 
 * *****************  Version 4  *****************
 * User: Toby         Date: 10/02/97   Time: 6:38p
 * Updated in $/GCS/Development/bluespaces/Java/com/ibm/bluespaces/examples/whiteboard
 * Changed most of these (copypaste thru Rhonda) to the new lower case com
 * model.  Also cleaned up a few deprecated APIs and got some old stuff
 * working (or at least commented out).  Will be back for the remaining
 * examples sometime later.
 * 
 * *****************  Version 2  *****************
 * User: Eichstam     Date: 8/12/97    Time: 6:34p
 * Updated in $/GCS/Development/Java/COM/ibm/almaden/tuplespace/examples/whiteboard
 * added the callback mechanism
 * 
 * *****************  Version 1  *****************
 * User: Eichstam     Date: 7/18/97    Time: 1:34a
 * Created in $/GCS/Development/Java/COM/ibm/almaden/tuplespace/examples/whiteboard
 * initial version of GCS 'shared' whiteboard
*/
/* $Log: WhiteboardPanel.java,v $
/* Revision 2.1.2.1  2000/02/05 14:52:31  jthomas
/* avoid System exit if applet
/*
/* Revision 2.1  1999/11/05 22:22:40  estesp
/* Update revision number to 2.1 on all files
/*
/* Revision 1.1.1.1  1999/11/05 16:24:53  estesp
/* Imported 2.1.0 release into Austin CVS
/*
 * Revision 1.5  1999/10/08 04:16:55  jthomas
 * no message
 *
 * Revision 1.4  1999/09/26 07:54:35  jthomas
 * Modify so it looks better on the Nino PDA
 *
 * Revision 1.3  1999/09/13 05:11:40  jthomas
 * cleanup
 *
 * Revision 1.2  1999/06/17 05:39:48  thodes
 *   Updated the inital checkin to append the "Log" field and
 * convert CR/LF to CR (for win/unix interop).
 *
 *   The inital checkin lower-cased directrory names, and omitted
 * many dirs/files that will added later, e.g., MoDAL stuff.
 *
 * All of the above will need to be done to all VSS-to-CVS
 * converted sources.  In summary, in moving from VSS to CVS, do this:
 *  - lower-case dir names
 *  - CR/LF --> CR
 *  - append CVS "Log" entties
 *
 * (a script that helps with #2 and #3 is in
 *     tspaces1:~thodes/bin/update-keywords.sh)
 * 
 */